Claims Management Fraud Detection

Portfólio Thiago Gonçalves Custódio

1. Descrição geral do problema

Definição: Fraud Detection é um conjunto de atividades realizadas para evitar que dinheiro ou propriedade sejam obtidos por meio de falsos pretextos.

Fraud Detection é aplicada a muitos setores, como bancos ou seguros. No setor de seguros, a fraude pode ser aplicada na alegação de um sinistro, onde investigações de sinistros de seguros se apoiam em evidências, entrevistas e registros para concluir se um sinistro é legítimo ou ilegítimo. Acidentes de carro, lesões corporais, lesões no local de trabalho e danos materiais são reivindicações de seguro comuns que exigem uma investigação.

A cada ano novas iniciativas são adotadas para reduzir as perdas com fraudes em sinistros e sem dúvidas que Machine Learning está cada vez mais presentes na solução de tais incidentes. Modelos de aprendizado de máquina são capazes de aprender com padrões de comportamento normal e são muito rápidos para se adaptar a mudanças desse comportamento identificando rapidamente padrões de transações fraudulentas. Isso significa que o modelo pode identificar sinistros suspeitos mesmo quando ainda não houve sequer uma investigação.

Objetivo: Neste projeto iremos utilizar a linguagem Python, para criar um modelo de aprendizagem de máquina que possa identificar sinistros suspeitos, e qual a probabilidade desta suspeita.

1.1 Informações sobre o DataSet

A fonte dos dados é pública disponibilizada no Kaggle com a finalidade de inspirar soluções em Data Science.

O conjunto de dados consiste em 39 atributos e 1.000 registros. O atributo Fraud_reported pode ser usado como o rótulo de classe, e possui como valores Y representando Houve fraude e N representando Não houve fraude.

2. Carregando Dados

2.1 Importando bibliotecas necessárias

Começaremos nosso projeto, importando todas as bibliotecas necessárias, para a realização das fases iniciais de exploração, e transformação dos dados (Data Munging).

In [1]:
# Importando biblioteca, para ocultar Future Warnings.
import warnings
warnings.simplefilter(action = 'ignore', category = FutureWarning)

# Importando bibliotecas, para a manipulação e exploração dos conjuntos de dados.
import numpy as np
import pandas as pd

# Importando módulos utilitários para Análise Exploratória/Estatística, 
# Pré-processamento/Feature Selection e Modelagem preditiva.
import utilAnaExplor as utlex
import utilScaleTransf as utlst
import utilPcaTransf as utlpca
import utilMachineLearning as utlml

# Importando bibliotecas, para balanceamento de classes e divisão do dataset.
import imblearn
from imblearn.over_sampling import SMOTE
from sklearn.model_selection import train_test_split

# Importando bibliotecas, para a etapa de modelagem preditiva.
from sklearn.feature_selection import SelectKBest, SelectPercentile, mutual_info_classif, f_classif, RFE, chi2
from mlxtend.feature_selection import SequentialFeatureSelector as SFS
import xgboost as xgb
from sklearn.ensemble import RandomForestClassifier, ExtraTreesClassifier, AdaBoostClassifier, GradientBoostingClassifier
import xgboost as xgb
from sklearn import tree
from sklearn.svm import SVC
from sklearn.naive_bayes import GaussianNB
from sklearn.tree import DecisionTreeClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import KFold, cross_val_score
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
from sklearn.ensemble import RandomForestClassifier, ExtraTreesClassifier, AdaBoostClassifier, GradientBoostingClassifier

# Importando classe, para fazer a busca dos melhores parâmetros, a serem utilizados em cada um dos modelos treinados.
from sklearn.model_selection import GridSearchCV

# Importando classes, para calcular as métricas de avaliação dos modelos preditivos.
from sklearn.metrics import accuracy_score, balanced_accuracy_score, average_precision_score, precision_score
from sklearn.metrics import recall_score, f1_score, roc_auc_score, cohen_kappa_score

# Versões dos pacotes usados neste jupyter notebook
%reload_ext watermark
%watermark -a "Thiago Gonçalves Custódio" --iversions
Author: Thiago Gonçalves Custódio

xgboost : 1.5.0
numpy   : 1.20.1
imblearn: 0.0
sklearn : 1.0.1
pandas  : 1.3.5

2.2 Carregando Dados

In [2]:
# Carregando os dados.
dataTrain = pd.read_csv('datasets/fraud_insurance_claims.csv')
In [3]:
# Exibindo as primeiras linhas do DataFrame.
dataTrain.head()
Out[3]:
months_as_customer age policy_number policy_bind_date policy_state policy_csl policy_deductable policy_annual_premium umbrella_limit insured_zip ... witnesses police_report_available total_claim_amount injury_claim property_claim vehicle_claim auto_make auto_model auto_year fraud_reported
0 328 48 521585 2014-10-17 00:00:00 OH 250/500 1000 1406.91 0 466132 ... 2 YES 71610 6510 13020 52080 Saab 92x 2004 Y
1 228 42 342868 2006-06-27 00:00:00 IN 250/500 2000 1197.22 5000000 468176 ... 0 ? 5070 780 780 3510 Mercedes E400 2007 Y
2 134 29 687698 2000-09-06 00:00:00 OH 100/300 2000 1413.14 5000000 430632 ... 3 NO 34650 7700 3850 23100 Dodge RAM 2007 N
3 256 41 227811 1990-05-25 00:00:00 IL 250/500 2000 1415.74 6000000 608117 ... 2 NO 63400 6340 6340 50720 Chevrolet Tahoe 2014 Y
4 228 44 367455 2014-06-06 00:00:00 IL 500/1000 1000 1583.91 6000000 610706 ... 1 NO 6500 1300 650 4550 Accura RSX 2009 N

5 rows × 39 columns

3. Data Munging - Preparando dados para a análise exploratória

3.1 Criando funções auxiliares

Iremos definir algumas funções, para facilitar a execução das etapas de Data Munging.

In [4]:
# Definindo uma função, para converter variáveis para o tipo categórico, e criar suas respectivas versões dummy.
def categoryToDummyVariables(data, columnsName):

    # Criando um dicionário vazio.
    newTypes = dict()
    
    # Criando o nome das variáveis dummy.
    newColumnsName = [n + '_dummy' for n in columnsName]

    # Definindo que cada variável especificada, deve ser convertida para o tipo de dado categórico.
    for i in range(0, len(columnsName)):
        newTypes.update({columnsName[i]: 'category'}) 

    # Convertendo o tipo de dado das variáveis especificadas.
    data = data.astype (newTypes)

    # Criando variáveis dummy.
    for i in range(0, len(columnsName)):
        data[newColumnsName[i]] = data[columnsName[i]].cat.codes

    # Retornando o DataFrame modificado.    
    return data
In [5]:
# Definindo uma função, para realizar as tarefas de Data Munging, necessárias para o conjunto de dados em análise.
def organizeData(data):      
    
    # Criando variáveis dummy para o conjunto de dados.
    data = categoryToDummyVariables(data = data, columnsName = data.select_dtypes(include = object).columns)
    
    # Eliminando as variáveis policy_number e incident_location do conjunto de dados.
    data = data.drop(labels = 'policy_number', axis = 1)   
    data = data.drop(labels = 'incident_location', axis = 1) 
    
    # Substituindo valores "?" por NA dentro do dataset para tratamento.
    data = data.replace('?',np.NaN)    
    
    # Tratamento de valores NA usando fillNa.

    # Substituindo '?' pela moda no atributo collision type.
    data['collision_type'].fillna(data['collision_type'].mode()[0], inplace = True)

    # Preencheremos como NO os casos de NA no atributo property_damage.
    data['property_damage'].fillna('NO', inplace = True)

    # Preencheremos como NO os casos de NA no atributo police_report_available.
    data['police_report_available'].fillna('NO', inplace = True)    
    
    # Retornando o DataFrame modificado.    
    return data

3.2 Visão geral dos dados

In [6]:
# Verificando as dimensões do dataset.
dataTrain.shape
Out[6]:
(1000, 39)

Verificamos a existência de 39 variáveis, e 1.000 observações dentro do dataset.

In [7]:
# Verificando o número de registros duplicados.
dataTrain.duplicated().sum()
Out[7]:
0

Detectamos 0 registros duplicados dentro do dataset.

In [8]:
# Verificando o número de NAs existentes dentro do dataset.
dataTrain.isna().sum().sum()
Out[8]:
0

Detectamos 0 registros valor NA dentro do dataset.

In [9]:
# Verificando o tipo de dados das variáveis do dataset.
dataTrain.dtypes.value_counts()
Out[9]:
object     21
int64      17
float64     1
dtype: int64

Verificamos a existência de 39 variáveis sendo 18 numéricas, e 21 variáveis categóricas dentro do dataset.

In [10]:
# Contabilizando o número de valores únicos, em cada variável do dataset de treino.
info = dataTrain.nunique().sort_values()

# Determinando o tipo de dado, de cada uma das variáveis, do dataset de treino.
info = pd.DataFrame(info.values, index = info.index, columns = ['NUniques'])

# Atribuindo informações, sobre o tipo de dado das variáveis, ao DataFrame.
info['dtypes'] = dataTrain.dtypes

# Exibindo DataFrame.
info
Out[10]:
NUniques dtypes
fraud_reported 2 object
insured_sex 2 object
police_report_available 3 object
bodily_injuries 3 int64
policy_state 3 object
policy_csl 3 object
policy_deductable 3 int64
property_damage 3 object
witnesses 4 int64
number_of_vehicles_involved 4 int64
incident_severity 4 object
incident_type 4 object
collision_type 4 object
authorities_contacted 5 object
insured_relationship 6 object
insured_education_level 7 object
incident_city 7 object
incident_state 7 object
umbrella_limit 11 int64
auto_make 14 object
insured_occupation 14 object
insured_hobbies 20 object
auto_year 21 int64
incident_hour_of_the_day 24 int64
auto_model 39 object
age 46 int64
incident_date 60 object
capital-gains 338 int64
capital-loss 354 int64
months_as_customer 391 int64
property_claim 626 int64
injury_claim 638 int64
vehicle_claim 726 int64
total_claim_amount 763 int64
policy_bind_date 951 object
policy_annual_premium 991 float64
insured_zip 995 int64
incident_location 1000 object
policy_number 1000 int64

3.3 Alterando tipos de dados das variáveis do dataset

Criaremos variáveis dummy para aquelas que forem do tipo categórico.

In [11]:
# Limpando e organizando o conjunto de dados de treino.
dataTrain = organizeData(data = dataTrain)

# Verificando o tipo de dados das variáveis do dataset.
dataTrain.dtypes.value_counts()
Out[11]:
int8        19
int64       16
int16        2
category     2
category     1
category     1
category     1
category     1
category     1
category     1
category     1
category     1
category     1
category     1
category     1
category     1
category     1
category     1
category     1
category     1
category     1
float64      1
category     1
dtype: int64

3.4 Criando cópia do dataset para análise exploratória

In [12]:
#  Criando uma cópia do Dataset para análise exploratória
df = dataTrain.copy(deep=True)

3.4.1 Alterando labels e tipos de dados das variáveis da cópia do dataset

In [13]:
# Alterando as variáveis para o tipo de dado categórico.
df['number_of_vehicles_involved'] = df['number_of_vehicles_involved'].astype('category')
df['witnesses'] = df['witnesses'].astype('category')
df['auto_year'] = df['auto_year'].astype('category')
df['incident_hour_of_the_day'] = df['incident_hour_of_the_day'].astype('category')

4. Análise exploratória dos dados

4.1 Explorando a distribuição da variável target

4.1.1 Variável Fraud Reported

In [14]:
# Definindo o nome da variável a ser analisada.
col = 'fraud_reported'

# Definindo a descrição da variável nos gráficos.
label = 'Fraud Reported'

# Contabilizando a frequência absoluta, de cada categoria presente na variável especificada.
dataCounts = df[col].value_counts()

# Plotando um gráfico de barras para a variável especificada.
utlex.plotBar (
    data = dataCounts,
    title = 'Frequência absoluta das categorias da Feature ' + col, 
    yaxis = 'Frequência Absoluta', 
    xaxis = label
)
In [15]:
# Plotando um gráfico de pizza para a variável especificada.
utlex.plotPie (
    data  = dataCounts, 
    title = 'Frequência relativa das categorias da feature ' + col
)

Registros que tiveram a variável fraud_reported representados pela label Yes equivalem a 24.7% do conjunto de dados, sendo assim nossa variável target está desbalanceada. Trataremos tal desvio mais a frente.

4.2 Explorando a distribuição de cada Feature a partir da variável Target

4.2.1 Variável Sexo do Segurado

In [16]:
# Definindo o nome da variável a ser analisada.
col = 'insured_sex'

# Definindo o nome da variável Target.
target = 'fraud_reported'

# Definindo a descrição da variável nos gráficos.
label = 'Sexo do Segurado'

# Capturando variáveis especificadas do Dataset.
data = df[[col, target]]

# Criando uma variável count para contabilizar as ocorrências de cada registro.
data['count'] = 1

# Agrupando dados e contabilizando o número de ocorrências.
data = data.groupby(by = [target, col]).sum()

# Reorganizando DataFrame. 
data = data.reset_index()

# Plotando um gráfico de barras para a variável especificada.
utlex.plotBar (
    data   = data,
    col    = col,
    target = target,
    title  = 'Fraud reported by ' + label,
    yaxis  = 'Frequência Absoluta',
    xaxis  = label, 
    kind   = 'groups'
)

4.2.2 Variável Police_report_available

In [17]:
# Definindo o nome da variável a ser analisada.
col = 'police_report_available'

# Definindo o nome da variável Target.
target = 'fraud_reported'

# Definindo a descrição da variável nos gráficos.
label = 'police_report_available'

# Capturando variáveis especificadas do Dataset.
data = dataTrain[[col, target]]

# Criando uma variável count para contabilizar as ocorrências de cada registro.
data['count'] = 1

# Agrupando dados e contabilizando o número de ocorrências.
data = data.groupby(by = [target, col]).sum()

# Reorganizando DataFrame. 
data = data.reset_index()

# Plotando um gráfico de barras para a variável especificada.
utlex.plotBar (
    data   = data,
    col    = col,
    target = target,
    title  = 'Fraud reported by ' + label,
    yaxis  = 'Frequência Absoluta',
    xaxis  = label, 
    kind   = 'groups'
)

4.2.3 Variável Policy_state

In [18]:
# Definindo o nome da variável a ser analisada.
col = 'policy_state'

# Definindo o nome da variável Target.
target = 'fraud_reported'

# Definindo a descrição da variável nos gráficos.
label = 'policy_state'

# Capturando variáveis especificadas do Dataset.
data = df[[col, target]]

# Criando uma variável count para contabilizar as ocorrências de cada registro.
data['count'] = 1

# Agrupando dados e contabilizando o número de ocorrências.
data = data.groupby(by = [target, col]).sum()

# Reorganizando DataFrame. 
data = data.reset_index()

# Plotando um gráfico de barras para a variável especificada.
utlex.plotBar (
    data   = data,
    col    = col,
    target = target,
    title  = 'Fraud reported by ' + label,
    yaxis  = 'Frequência Absoluta',
    xaxis  = label, 
    kind   = 'groups'
)

4.2.4 Variável Property_damage

In [19]:
# Definindo o nome da variável a ser analisada.
col = 'property_damage'

# Definindo o nome da variável Target.
target = 'fraud_reported'

# Definindo a descrição da variável nos gráficos.
label = 'property_damage'

# Capturando variáveis especificadas do Dataset.
data = df[[col, target]]

# Criando uma variável count para contabilizar as ocorrências de cada registro.
data['count'] = 1

# Agrupando dados e contabilizando o número de ocorrências.
data = data.groupby(by = [target, col]).sum()

# Reorganizando DataFrame. 
data = data.reset_index()

# Plotando um gráfico de barras para a variável especificada.
utlex.plotBar (
    data   = data,
    col    = col,
    target = target,
    title  = 'Fraud reported by ' + label,
    yaxis  = 'Frequência Absoluta',
    xaxis  = label, 
    kind   = 'groups'
)

4.2.5 Variável Incident_severity

In [20]:
# Definindo o nome da variável a ser analisada.
col = 'incident_severity'

# Definindo o nome da variável Target.
target = 'fraud_reported'

# Definindo a descrição da variável nos gráficos.
label = 'incident_severity'

# Capturando variáveis especificadas do Dataset.
data = df[[col, target]]

# Criando uma variável count para contabilizar as ocorrências de cada registro.
data['count'] = 1

# Agrupando dados e contabilizando o número de ocorrências.
data = data.groupby(by = [target, col]).sum()

# Reorganizando DataFrame. 
data = data.reset_index()

# Plotando um gráfico de barras para a variável especificada.
utlex.plotBar (
    data   = data,
    col    = col,
    target = target,
    title  = 'Fraud reported by ' + label,
    yaxis  = 'Frequência Absoluta',
    xaxis  = label, 
    kind   = 'groups'
)

4.2.6 Variável Incident_type

In [21]:
# Definindo o nome da variável a ser analisada.
col = 'incident_type'

# Definindo o nome da variável Target.
target = 'fraud_reported'

# Definindo a descrição da variável nos gráficos.
label = 'incident_type'

# Capturando variáveis especificadas do Dataset.
data = df[[col, target]]

# Criando uma variável count para contabilizar as ocorrências de cada registro.
data['count'] = 1

# Agrupando dados e contabilizando o número de ocorrências.
data = data.groupby(by = [target, col]).sum()

# Reorganizando DataFrame. 
data = data.reset_index()

# Plotando um gráfico de barras para a variável especificada.
utlex.plotBar (
    data   = data,
    col    = col,
    target = target,
    title  = 'Fraud reported by ' + label,
    yaxis  = 'Frequência Absoluta',
    xaxis  = label, 
    kind   = 'groups'
)

4.2.7 Variável Collision_type

In [22]:
# Definindo o nome da variável a ser analisada.
col = 'collision_type'

# Definindo o nome da variável Target.
target = 'fraud_reported'

# Definindo a descrição da variável nos gráficos.
label = 'collision_type'

# Capturando variáveis especificadas do Dataset.
data = df[[col, target]]

# Criando uma variável count para contabilizar as ocorrências de cada registro.
data['count'] = 1

# Agrupando dados e contabilizando o número de ocorrências.
data = data.groupby(by = [target, col]).sum()

# Reorganizando DataFrame. 
data = data.reset_index()

# Plotando um gráfico de barras para a variável especificada.
utlex.plotBar (
    data   = data,
    col    = col,
    target = target,
    title  = 'Fraud reported by ' + label,
    yaxis  = 'Frequência Absoluta',
    xaxis  = label, 
    kind   = 'groups'
)

4.2.8 Variável Authorities_contacted

In [23]:
# Definindo o nome da variável a ser analisada.
col = 'authorities_contacted'

# Definindo o nome da variável Target.
target = 'fraud_reported'

# Definindo a descrição da variável nos gráficos.
label = 'authorities_contacted'

# Capturando variáveis especificadas do Dataset.
data = df[[col, target]]

# Criando uma variável count para contabilizar as ocorrências de cada registro.
data['count'] = 1

# Agrupando dados e contabilizando o número de ocorrências.
data = data.groupby(by = [target, col]).sum()

# Reorganizando DataFrame. 
data = data.reset_index()

# Plotando um gráfico de barras para a variável especificada.
utlex.plotBar (
    data   = data,
    col    = col,
    target = target,
    title  = 'Fraud reported by ' + label,
    yaxis  = 'Frequência Absoluta',
    xaxis  = label, 
    kind   = 'groups'
)

4.2.9 Variável Insured_relationship

In [24]:
# Definindo o nome da variável a ser analisada.
col = 'insured_relationship'

# Definindo o nome da variável Target.
target = 'fraud_reported'

# Definindo a descrição da variável nos gráficos.
label = 'insured_relationship'

# Capturando variáveis especificadas do Dataset.
data = df[[col, target]]

# Criando uma variável count para contabilizar as ocorrências de cada registro.
data['count'] = 1

# Agrupando dados e contabilizando o número de ocorrências.
data = data.groupby(by = [target, col]).sum()

# Reorganizando DataFrame. 
data = data.reset_index()

# Plotando um gráfico de barras para a variável especificada.
utlex.plotBar (
    data   = data,
    col    = col,
    target = target,
    title  = 'Fraud reported by ' + label,
    yaxis  = 'Frequência Absoluta',
    xaxis  = label, 
    kind   = 'groups'
)

4.2.10 Variável Insured_education_level

In [25]:
# Definindo o nome da variável a ser analisada.
col = 'insured_education_level'

# Definindo o nome da variável Target.
target = 'fraud_reported'

# Definindo a descrição da variável nos gráficos.
label = 'insured_education_level'

# Capturando variáveis especificadas do Dataset.
data = df[[col, target]]

# Criando uma variável count para contabilizar as ocorrências de cada registro.
data['count'] = 1

# Agrupando dados e contabilizando o número de ocorrências.
data = data.groupby(by = [target, col]).sum()

# Reorganizando DataFrame. 
data = data.reset_index()

# Plotando um gráfico de barras para a variável especificada.
utlex.plotBar (
    data   = data,
    col    = col,
    target = target,
    title  = 'Fraud reported by ' + label,
    yaxis  = 'Frequência Absoluta',
    xaxis  = label, 
    kind   = 'groups'
)

4.2.11 Variável Incident_city

In [26]:
# Definindo o nome da variável a ser analisada.
col = 'incident_city'

# Definindo o nome da variável Target.
target = 'fraud_reported'

# Definindo a descrição da variável nos gráficos.
label = 'incident_city'

# Capturando variáveis especificadas do Dataset.
data = df[[col, target]]

# Criando uma variável count para contabilizar as ocorrências de cada registro.
data['count'] = 1

# Agrupando dados e contabilizando o número de ocorrências.
data = data.groupby(by = [target, col]).sum()

# Reorganizando DataFrame. 
data = data.reset_index()

# Plotando um gráfico de barras para a variável especificada.
utlex.plotBar (
    data   = data,
    col    = col,
    target = target,
    title  = 'Fraud reported by ' + label,
    yaxis  = 'Frequência Absoluta',
    xaxis  = label, 
    kind   = 'groups'
)

4.2.12 Variável Incident_state

In [27]:
# Definindo o nome da variável a ser analisada.
col = 'incident_state'

# Definindo o nome da variável Target.
target = 'fraud_reported'

# Definindo a descrição da variável nos gráficos.
label = 'incident_state'

# Capturando variáveis especificadas do Dataset.
data = df[[col, target]]

# Criando uma variável count para contabilizar as ocorrências de cada registro.
data['count'] = 1

# Agrupando dados e contabilizando o número de ocorrências.
data = data.groupby(by = [target, col]).sum()

# Reorganizando DataFrame. 
data = data.reset_index()

# Plotando um gráfico de barras para a variável especificada.
utlex.plotBar (
    data   = data,
    col    = col,
    target = target,
    title  = 'Fraud reported by ' + label,
    yaxis  = 'Frequência Absoluta',
    xaxis  = label, 
    kind   = 'groups'
)

4.2.13 Variável Auto_make

In [28]:
# Definindo o nome da variável a ser analisada.
col = 'auto_make'

# Definindo o nome da variável Target.
target = 'fraud_reported'

# Definindo a descrição da variável nos gráficos.
label = 'auto_make'

# Capturando variáveis especificadas do Dataset.
data = df[[col, target]]

# Criando uma variável count para contabilizar as ocorrências de cada registro.
data['count'] = 1

# Agrupando dados e contabilizando o número de ocorrências.
data = data.groupby(by = [target, col]).sum()

# Reorganizando DataFrame. 
data = data.reset_index()

# Plotando um gráfico de barras para a variável especificada.
utlex.plotBar (
    data   = data,
    col    = col,
    target = target,
    title  = 'Fraud reported by ' + label,
    yaxis  = 'Frequência Absoluta',
    xaxis  = label, 
    kind   = 'groups'
)

4.2.14 Variável Insured_occupation

In [29]:
# Definindo o nome da variável a ser analisada.
col = 'insured_occupation'

# Definindo o nome da variável Target.
target = 'fraud_reported'

# Definindo a descrição da variável nos gráficos.
label = 'insured_occupation'

# Capturando variáveis especificadas do Dataset.
data = df[[col, target]]

# Criando uma variável count para contabilizar as ocorrências de cada registro.
data['count'] = 1

# Agrupando dados e contabilizando o número de ocorrências.
data = data.groupby(by = [target, col]).sum()

# Reorganizando DataFrame. 
data = data.reset_index()

# Plotando um gráfico de barras para a variável especificada.
utlex.plotBar (
    data   = data,
    col    = col,
    target = target,
    title  = 'Fraud reported by ' + label,
    yaxis  = 'Frequência Absoluta',
    xaxis  = label, 
    kind   = 'groups'
)

4.2.15 Variável Insured_hobbies

In [30]:
# Definindo o nome da variável a ser analisada.
col = 'insured_hobbies'

# Definindo o nome da variável Target.
target = 'fraud_reported'

# Definindo a descrição da variável nos gráficos.
label = 'insured_hobbies'

# Capturando variáveis especificadas do Dataset.
data = df[[col, target]]

# Criando uma variável count para contabilizar as ocorrências de cada registro.
data['count'] = 1

# Agrupando dados e contabilizando o número de ocorrências.
data = data.groupby(by = [target, col]).sum()

# Reorganizando DataFrame. 
data = data.reset_index()

# Plotando um gráfico de barras para a variável especificada.
utlex.plotBar (
    data   = data,
    col    = col,
    target = target,
    title  = 'Fraud reported by ' + label,
    yaxis  = 'Frequência Absoluta',
    xaxis  = label, 
    kind   = 'groups'
)

4.2.16 Variável Auto_model

In [31]:
# Definindo o nome da variável a ser analisada.
col = 'auto_model'

# Definindo o nome da variável Target.
target = 'fraud_reported'

# Definindo a descrição da variável nos gráficos.
label = 'auto_model'

# Capturando variáveis especificadas do Dataset.
data = df[[col, target]]

# Criando uma variável count para contabilizar as ocorrências de cada registro.
data['count'] = 1

# Agrupando dados e contabilizando o número de ocorrências.
data = data.groupby(by = [target, col]).sum()

# Reorganizando DataFrame. 
data = data.reset_index()

# Plotando um gráfico de barras para a variável especificada.
utlex.plotBar (
    data   = data,
    col    = col,
    target = target,
    title  = 'Fraud reported by ' + label,
    yaxis  = 'Frequência Absoluta',
    xaxis  = label, 
    kind   = 'groups'
)

4.2.17 Variável Incident_date

In [32]:
# Definindo o nome da variável a ser analisada.
col = 'incident_date'

# Definindo o nome da variável Target.
target = 'fraud_reported'

# Definindo a descrição da variável nos gráficos.
label = 'incident_date'

# Capturando variáveis especificadas do Dataset.
data = df[[col, target]]

# Criando uma variável count para contabilizar as ocorrências de cada registro.
data['count'] = 1

# Agrupando dados e contabilizando o número de ocorrências.
data = data.groupby(by = [target, col]).sum()

# Reorganizando DataFrame. 
data = data.reset_index()

# Plotando um gráfico de barras para a variável especificada.
utlex.plotBar (
    data   = data,
    col    = col,
    target = target,
    title  = 'Fraud reported by ' + label,
    yaxis  = 'Frequência Absoluta',
    xaxis  = label, 
    kind   = 'groups'
)

4.2.18 Variável Number_of_vehicles_involved

In [33]:
# Definindo o nome da variável a ser analisada.
col = 'number_of_vehicles_involved'

# Definindo o nome da variável Target.
target = 'fraud_reported'

# Definindo a descrição da variável nos gráficos.
label = 'number_of_vehicles_involved'

# Capturando variáveis especificadas do Dataset.
data = df[[col, target]]

# Criando uma variável count para contabilizar as ocorrências de cada registro.
data['count'] = 1

# Agrupando dados e contabilizando o número de ocorrências.
data = data.groupby(by = [target, col]).sum()

# Reorganizando DataFrame. 
data = data.reset_index()

# Plotando um gráfico de barras para a variável especificada.
utlex.plotBar (
    data   = data,
    col    = col,
    target = target,
    title  = 'Fraud reported by ' + label,
    yaxis  = 'Frequência Absoluta',
    xaxis  = label, 
    kind   = 'groups'
)

4.2.19 Variável Witnesses

In [34]:
# Definindo o nome da variável a ser analisada.
col = 'witnesses'

# Definindo o nome da variável Target.
target = 'fraud_reported'

# Definindo a descrição da variável nos gráficos.
label = 'witnesses'

# Capturando variáveis especificadas do Dataset.
data = df[[col, target]]

# Criando uma variável count para contabilizar as ocorrências de cada registro.
data['count'] = 1

# Agrupando dados e contabilizando o número de ocorrências.
data = data.groupby(by = [target, col]).sum()

# Reorganizando DataFrame. 
data = data.reset_index()

# Plotando um gráfico de barras para a variável especificada.
utlex.plotBar (
    data   = data,
    col    = col,
    target = target,
    title  = 'Fraud reported by ' + label,
    yaxis  = 'Frequência Absoluta',
    xaxis  = label, 
    kind   = 'groups'
)

4.2.20 Variável Auto_year

In [35]:
# Definindo o nome da variável a ser analisada.
col = 'auto_year'

# Definindo o nome da variável Target.
target = 'fraud_reported'

# Definindo a descrição da variável nos gráficos.
label = 'auto_year'

# Capturando variáveis especificadas do Dataset.
data = df[[col, target]]

# Criando uma variável count para contabilizar as ocorrências de cada registro.
data['count'] = 1

# Agrupando dados e contabilizando o número de ocorrências.
data = data.groupby(by = [target, col]).sum()

# Reorganizando DataFrame. 
data = data.reset_index()

# Plotando um gráfico de barras para a variável especificada.
utlex.plotBar (
    data   = data,
    col    = col,
    target = target,
    title  = 'Fraud reported by ' + label,
    yaxis  = 'Frequência Absoluta',
    xaxis  = label, 
    kind   = 'groups'
)

4.2.21 Variável Incident_hour_of_the_day

In [36]:
# Definindo o nome da variável a ser analisada.
col = 'incident_hour_of_the_day'

# Definindo o nome da variável Target.
target = 'fraud_reported'

# Definindo a descrição da variável nos gráficos.
label = 'incident_hour_of_the_day'

# Capturando variáveis especificadas do Dataset.
data = df[[col, target]]

# Criando uma variável count para contabilizar as ocorrências de cada registro.
data['count'] = 1

# Agrupando dados e contabilizando o número de ocorrências.
data = data.groupby(by = [target, col]).sum()

# Reorganizando DataFrame. 
data = data.reset_index()

# Plotando um gráfico de barras para a variável especificada.
utlex.plotBar (
    data   = data,
    col    = col,
    target = target,
    title  = 'Fraud reported by ' + label,
    yaxis  = 'Frequência Absoluta',
    xaxis  = label, 
    kind   = 'groups'
)

Medidas de Assimetria e Curtose

O coeficente de Assimetria (Skewness), indica como os dados estão distribuídos, e para interpretar seu resultado podemos olhar a tabela a seguir:

Índice de Assimetria Descrição:
SK ≈ 0 Os dados são simétricos. Tanto a cauda do lado direito, quanto a do lado esquerdo da função densidade de probabilidade, são iguais;
SK < 0 A assimetria é negativa. A cauda do lado esquerdo da função densidade de probabilidade, é maior que a do lado direito e;
SK > 0 A assimetria é positiva. A cauda do lado direito da função densidade de probabilidade, é maior que a do lado esquerdo.

O coeficiente de Curtose (Kurtosis), é uma medida que caracteriza o achatamento da curva da função de distribuição, e para interpretar seu resultado, podemos olhar a tabela a seguir:

Índice de Curtose Descrição:
CK ≈ 0 A distribuição é normal, e é chamada de Curtose Mesocúrtica;
CK < 0 A Cauda é mais leve que a normal. Para um coeficiente de Curtose negativo, tem-se uma Curtose Platicúrtica e;
CK > 0 A Cauda é mais pesada que a normal. Para um coeficiente de Curtose positivo, tem-se uma Curtose Leptocúrtica.

4.2.22 Variável Age

In [37]:
# Definindo o nome da variável a ser analisada.
col = 'age'

# Definindo o nome da variável Target.
target = 'fraud_reported'

# Definindo a descrição da variável nos gráficos.
label = 'age'

# Capturando variáveis especificadas do Dataset.
data = df[[col, target]]

# Criando uma variável count para contabilizar as ocorrências de cada registro.
data['count'] = 1

# Agrupando dados e contabilizando o número de ocorrências.
data = data.groupby(by = [target, col]).sum()

# Reorganizando DataFrame. 
data = data.reset_index()

# Plotando um gráfico de barras para a variável especificada.
utlex.plotBar (
    data   = data,
    col    = col,
    target = target,
    title  = 'Fraud reported by ' + label,
    yaxis  = 'Frequência Absoluta',
    xaxis  = label, 
    kind   = 'groups'
)
In [38]:
# Criando um gráfico de Densidade para a variável especificada.
utlex.plotDensity (
    data   = df[[col, target]], 
    title  = 'Gráfico de Densidade Fraud reported by ' + col, 
    xaxis  = label,
    col    = col,
    target = target,
    group  = True
)
In [39]:
# Plotando um gráfico de boxplot para a variável especificada.
utlex.plotBoxplot (
    data   = df[[col, target]],
    title  = 'Boxplot Fraud reported by ' + col,
    yaxis  = label,
    xaxis  = target.capitalize(),
    col    = col,
    target = target,
    kind   = 'groups'
)
In [40]:
# Calculando algumas estatísticas para a variável especificada.
utlex.varStats(col = col, data = df, target = target)
Out[40]:
min Q1 Median Mean Q3 SD Sk Ck
fraud_reported
N 20 32.0 38.0 38.884462 44.0 8.973139 0.471029 -0.225690
Y 19 32.0 38.0 39.141700 45.0 9.648295 0.491270 -0.400452

4.2.23 Variável Months_as_customer

In [41]:
# Definindo o nome da variável a ser analisada.
col = 'months_as_customer'

# Definindo o nome da variável Target.
target = 'fraud_reported'

# Definindo a descrição da variável nos gráficos.
label = 'months_as_customer'

# Capturando variáveis especificadas do Dataset.
data = df[[col, target]]

# Criando uma variável count para contabilizar as ocorrências de cada registro.
data['count'] = 1

# Agrupando dados e contabilizando o número de ocorrências.
data = data.groupby(by = [target, col]).sum()

# Reorganizando DataFrame. 
data = data.reset_index()

# Plotando um gráfico de barras para a variável especificada.
utlex.plotBar (
    data   = data,
    col    = col,
    target = target,
    title  = 'Fraud reported by ' + label,
    yaxis  = 'Frequência Absoluta',
    xaxis  = label, 
    kind   = 'groups'
)
In [42]:
# Criando um gráfico de Densidade para a variável especificada.
utlex.plotDensity (
    data   = df[[col, target]], 
    title  = 'Gráfico de Densidade Fraud reported by ' + col, 
    xaxis  = label,
    col    = col,
    target = target,
    group  = True
)
In [43]:
# Plotando um gráfico de boxplot para a variável especificada.
utlex.plotBoxplot (
    data   = df[[col, target]],
    title  = 'Boxplot Fraud reported by ' + col,
    yaxis  = label,
    xaxis  = target.capitalize(),
    col    = col,
    target = target,
    kind   = 'groups'
)
In [44]:
# Calculando algumas estatísticas para a variável especificada.
utlex.varStats(col = col, data = df, target = target)
Out[44]:
min Q1 Median Mean Q3 SD Sk Ck
fraud_reported
N 0 115.0 200.0 202.600266 276.0 113.574565 0.370000 -0.440805
Y 3 116.0 199.0 208.080972 279.0 119.824064 0.333265 -0.630864

4.3 Analisando a correlação entre as variáveis

Nesta etapa, desejamos verificar como as variáveis se correlacionam, ou seja, como uma variável ajuda a prever o valor de outra variável no dataset.

In [45]:
# Criando uma matriz de correlação.
corr = dataTrain.corr()

# Selecionando o triângulo superior da matriz de correlação.
upper = corr.abs().where(np.triu(np.ones(corr.shape), k = 1).astype(bool))

# Capturando o nome das variáveis que apresentam uma correlação maior do que 0.95.
to_drop = [column for column in upper.columns if any(upper[column] > 0.95)]

# Exibindo o nome das variáveis altamente correlacionadas.
pd.DataFrame(data = to_drop, columns = ['Highly correlated'])
Out[45]:
Highly correlated
0 vehicle_claim
In [46]:
# Plotando a matriz de correlação entre as variáveis do DataFrame.
utlex.plotCorr(corr)

Detectamos a existência de 1 variável altamente correlacionada vehicle_claim, e esta deverá ser eliminada do conjuntos de dados.

Observamos que a variável total_claim_amount é a que apresenta a correlação mais fortes com a variável a ser prevista.

5. Pré-Processamento - Modelagem Preditiva

5.1 Extraindo Features dos conjuntos de dados

In [47]:
# Eliminando as variáveis altamente correlacionadas do conjunto de dados.
dataTrain = dataTrain.drop(to_drop, axis = 1)
In [48]:
# Capturando o nome das colunas do tipo categórico presentes no DataFrame.
categ = dataTrain.select_dtypes(['category']).columns

# Capturando a variável target do conjunto de dados.
trainTarget = dataTrain['fraud_reported_dummy']

# Eliminando a variável target do conjunto de dados.
trainFeatures = dataTrain.drop(labels = 'fraud_reported_dummy', axis = 1)

# Eliminando as variáveis categóricas do conjunto de dados de treino e de teste.
trainFeatures = trainFeatures.drop(labels = categ, axis = 1)
In [49]:
# Verificando as novas dimensões do DataFrame de treino.
trainFeatures.shape
Out[49]:
(1000, 36)
In [50]:
# Verificando as novas dimensões do DataFrame de treino.
trainTarget.shape
Out[50]:
(1000,)

5.2 Balanceando variável target

In [51]:
# Seed para reproduzir o mesmo resultado
seed = 100

# Cria o balanceador SMOTE
smote_bal = SMOTE(random_state = seed)

# Aplica o balanceador
trainFeatures_res, trainTarget_res = smote_bal.fit_resample(trainFeatures, trainTarget)
In [52]:
# Shape dos dados originais
trainFeatures.shape
Out[52]:
(1000, 36)
In [53]:
# Shape dos dados reamostrados 
trainFeatures_res.shape
Out[53]:
(1506, 36)
In [54]:
# Shape dos dados reamostrados 
trainTarget_res.shape
Out[54]:
(1506,)
In [55]:
# Convertendo Serie dados reamostrados variavel target para dataframe.
df = trainTarget_res.to_frame()

# Atribuindo labels diferentes para as categorias da variável target.
df['fraud_reported_dummy'] = ['Y' if v == 1 else 'N' for v in df['fraud_reported_dummy']]

# Alterando a variável target para o tipo de dado categórico.

df['fraud_reported_dummy'] = df['fraud_reported_dummy'].astype('category')
In [56]:
# Definindo o nome da variável a ser analisada.
col = 'fraud_reported_dummy'

# Definindo a descrição da variável nos gráficos.
label = 'Fraud Reported'

# Contabilizando a frequência absoluta, de cada categoria presente na variável especificada.
dataCounts = df[col].value_counts()

# Plotando um gráfico de barras para a variável especificada.
utlex.plotBar (
    data = dataCounts,
    title = 'Frequência absoluta das categorias da Feature ' + col + ' após balanceamento de classe', 
    yaxis = 'Frequência Absoluta', 
    xaxis = label
)
In [57]:
# Plotando um gráfico de pizza para a variável especificada.
utlex.plotPie (
    data  = dataCounts, 
    title = 'Frequência relativa das categorias da feature ' + col + ' após balanceamento de classe'
)

Agora que nossa variável target esta balanceada podemos seguir com a divisão dos dados em treino e teste e a seleção das melhores variáveis para a modelagem preditiva.

5.3 Divisão dos Dados em Treino e Teste

In [58]:
# Divisão em Dados de Treino e Teste.
trainFeatures, testFeatures, trainTarget, testTarget = train_test_split(trainFeatures_res, trainTarget_res, test_size = 0.3, random_state = 100)

6. Feature Selection

6.1 Aplicando diferentes escalas as Features de Treino e de Teste

Nesta etapa, iremos aplicar diferentes transformações, nas variáveis preditoras dos conjuntos de dados de treino e de teste.

In [59]:
# Aplicando a transformação MinMaxScaler, as Features do conjunto de dados de treino e de teste.
trainFeaturesMM, testFeaturesMM = utlst.dataTransform (
    train     = trainFeatures,
    test      = testFeatures,
    transform = 'MM'
)
In [60]:
# Aplicando a transformação StandardScaler, as Features do conjunto de dados de treino e de teste.
trainFeaturesSS, testFeaturesSS = utlst.dataTransform (
    train     = trainFeatures,
    test      = testFeatures,
    transform = 'SS'
)
In [61]:
# Aplicando a transformação Yeo-Johnson, as Features do conjunto de dados de treino e de teste.
trainFeaturesNormDistribuition, testFeaturesNormDistribuition = utlst.dataTransform (
    train     = trainFeatures,
    test      = testFeatures,
    transform = 'ND'
)
In [62]:
# Aplicando a transformação Normalize, as Features do conjunto de dados de treino e de teste.
trainFeaturesNormalized, testFeaturesNormalized = utlst.dataTransform (
    train     = trainFeatures,
    test      = testFeatures,
    transform = 'N'
)

6.2 Aplicando técnicas de Features Selection

Aplicaremos diferentes técnicas de Feature Selection, para determinar qual é a melhor combinação de variáveis preditoras a ser utilizada.

6.2.1 SelectKBest

Este método seleciona recursos de acordo com as k pontuações mais altas.

In [63]:
# Definindo qual conjunto de dados, já escalado, deve ser utilizado.
tFeatures = trainFeaturesMM

# Instanciando um objeto da classe SelectKBest, para selecionar as melhores variáveis preditoras.
skb = SelectKBest(chi2, k = 15)

# Capturando os scores das variáveis preditoras.
bestFeatuesSKB = skb.fit_transform(tFeatures, trainTarget)

# Capturando o nome das variáveis preditoras.
bfSkb = tFeatures.columns[skb.get_support()]

# Exibindo o nome das variáveis preditoras.
bfSkb
Out[63]:
Index(['bodily_injuries', 'total_claim_amount', 'injury_claim',
       'property_claim', 'policy_state_dummy', 'policy_csl_dummy',
       'insured_sex_dummy', 'insured_hobbies_dummy', 'incident_type_dummy',
       'incident_severity_dummy', 'authorities_contacted_dummy',
       'incident_state_dummy', 'incident_city_dummy', 'property_damage_dummy',
       'police_report_available_dummy'],
      dtype='object')
In [64]:
# Criando um DataFrame, com os scores obtidos para cada uma das Features, segundo a técnica utilizada.
sc = pd.Series(skb.scores_, index = tFeatures.columns)

# Capturando os scores das variáveis preditoras.
sc = sc[skb.get_support()]

# Ordenando o Dataframe com os scores.
sc = sc.sort_values(ascending = False)
In [65]:
# Plotando um gráfico de barras, dos scores gerados para as features, a partir da técnica utilizada.
utlex.plotBar (
    data        = sc,
    title       = 'Scores das melhores features com o SelectKBest', 
    yaxis       = 'Features', 
    xaxis       = 'Scores',
    orientation = 'h'
)

6.2.2 Information Gain

O Information gain ou Mutual information mede quanta informação a presença / ausência de um recurso contribui para fazer a previsão correta da variável target.

In [66]:
# Definindo qual conjunto de dados, já escalado, deve ser utilizado.
tFeatures = trainFeaturesMM

# Instanciando um objeto da classe mutual_info_classif.
bestFeatuesIG = mutual_info_classif(tFeatures, trainTarget, discrete_features = 'auto', n_neighbors = 3)

# Inserindo Scores obtidos em uma Série temporal.
scoreFeatures = pd.Series(bestFeatuesIG, index = tFeatures.columns)

# Capturando os scores das variáveis preditoras em ordem decrescente.
bfIg = scoreFeatures.sort_values(ascending = False)
In [67]:
# Plotando um gráfico de barras, dos scores gerados para as features, a partir da técnica utilizada.
utlex.plotBar (
    data        = bfIg,
    title       = 'Scores das melhores features com o Information Gain', 
    yaxis       = 'Features', 
    xaxis       = 'Scores', 
    orientation = 'h'
)
In [68]:
# Capturando o nome das variáveis preditoras.
bfIg = bfIg.index

# Exibindo o nome das variáveis preditoras.
bfIg
Out[68]:
Index(['incident_severity_dummy', 'policy_deductable', 'incident_state_dummy',
       'total_claim_amount', 'incident_date_dummy', 'injury_claim',
       'incident_type_dummy', 'collision_type_dummy', 'insured_hobbies_dummy',
       'authorities_contacted_dummy', 'insured_zip', 'property_claim',
       'number_of_vehicles_involved', 'policy_annual_premium',
       'policy_csl_dummy', 'capital-loss', 'auto_model_dummy', 'witnesses',
       'property_damage_dummy', 'age', 'auto_make_dummy', 'capital-gains',
       'insured_education_level_dummy', 'police_report_available_dummy',
       'umbrella_limit', 'incident_hour_of_the_day', 'policy_bind_date_dummy',
       'insured_sex_dummy', 'incident_location_dummy', 'policy_state_dummy',
       'bodily_injuries', 'incident_city_dummy', 'auto_year',
       'insured_relationship_dummy', 'insured_occupation_dummy',
       'months_as_customer'],
      dtype='object')

6.2.3 ANOVA F-value

Se os recursos forem categóricos, calcularemos uma estatística qui-quadrado entre cada recurso e a variável target. No entanto, se os recursos forem quantitativos, calcularemos a ANOVA F-Value entre cada recurso e a variável target.

As pontuações do F-Value examinam se, quando agrupamos a característica numérica pela variável target, as médias para cada grupo se tornam significativamente diferentes.

In [69]:
# Definindo qual conjunto de dados, já escalado, deve ser utilizado.
tFeatures = trainFeaturesMM

# Instanciando um objeto da classe SelectKBest para selecionar as melhores variáveis preditoras a partir dos
# scores ANOVA F-Values.
skb = SelectKBest(f_classif, k = 15)

# Capturando as variáveis preditoras.
bestFeatuesANOVA = skb.fit_transform(tFeatures, trainTarget)

# Capturando o nome das variáveis preditoras.
bfAnova = tFeatures.columns[skb.get_support()]

# Exibindo o nome das variáveis preditoras.
bfAnova
Out[69]:
Index(['bodily_injuries', 'total_claim_amount', 'injury_claim',
       'property_claim', 'policy_state_dummy', 'policy_csl_dummy',
       'insured_sex_dummy', 'insured_hobbies_dummy', 'incident_type_dummy',
       'incident_severity_dummy', 'authorities_contacted_dummy',
       'incident_state_dummy', 'incident_city_dummy', 'property_damage_dummy',
       'police_report_available_dummy'],
      dtype='object')
In [70]:
# Criando uma Série Temporal com os scores obtidos para cada uma das Features segundo a técnica utilizada.
sc = pd.Series(skb.scores_, index = tFeatures.columns)

# Capturando os scores das variáveis preditoras.
sc = sc[skb.get_support()]

# Ordenando a Série Temporal em ordem decrescente dos scores.
sc = sc.sort_values(ascending = False)
In [71]:
# Plotando um gráfico de barras, dos scores gerados para as features, a partir da técnica utilizada.
utlex.plotBar (
    data        = sc,
    title       = 'Scores das melhores features com o ANOVA F-value', 
    yaxis       = 'Features', 
    xaxis       = 'Scores', 
    orientation = 'h'
)

6.2.4 Forward Selection

O Forward Selection é um método iterativo, no qual começamos sem ter nenhum recurso no modelo. A cada iteração, adicionamos uma variável que melhora o modelo e efetuamos este procedimento até que a performance do modelo pare de evoluir.

A seleção de recursos começa avaliando todas as variáveis individualmente, e seleciona aquela que gera o algoritmo com o melhor desempenho, de acordo com um critério de avaliação predefinido. Em seguida, se avalia todas as combinações possíveis das variáveis já selecionadas e dos recursos ainda não escolhidos para definir a combinação que produz o algoritmo com a melhor performance, com base nos mesmos critérios predefinidos.

In [72]:
# Definindo qual conjunto de dados, já escalado, deve ser utilizado.
tFeatures = trainFeaturesMM

# Instanciando um objeto da classe SFS para selecionar as melhores variáveis preditoras segundo sua acurácia, 
# utilizando o algoritmo XGBClassifer.
sfs = SFS (
    estimator  = xgb.XGBClassifier(use_label_encoder=False,eval_metric='logloss'), 
    k_features = 15,
    forward    = True, 
    floating   = False, 
    verbose    = 2,
    scoring    = 'accuracy',
    cv         = 3
)

# Capturando as variáveis preditoras.
sfs = sfs.fit(
    X = tFeatures, 
    y = trainTarget
)
[Parallel(n_jobs=1)]: Using backend SequentialBackend with 1 concurrent workers.
[Parallel(n_jobs=1)]: Done   1 out of   1 | elapsed:    0.5s remaining:    0.0s
[Parallel(n_jobs=1)]: Done  36 out of  36 | elapsed:    5.8s finished

[2022-02-15 13:21:25] Features: 1/15 -- score: 0.8159371492704826[Parallel(n_jobs=1)]: Using backend SequentialBackend with 1 concurrent workers.
[Parallel(n_jobs=1)]: Done   1 out of   1 | elapsed:    0.2s remaining:    0.0s
[Parallel(n_jobs=1)]: Done  35 out of  35 | elapsed:    6.6s finished

[2022-02-15 13:21:31] Features: 2/15 -- score: 0.8548357506690839[Parallel(n_jobs=1)]: Using backend SequentialBackend with 1 concurrent workers.
[Parallel(n_jobs=1)]: Done   1 out of   1 | elapsed:    0.2s remaining:    0.0s
[Parallel(n_jobs=1)]: Done  34 out of  34 | elapsed:   10.7s finished

[2022-02-15 13:21:42] Features: 3/15 -- score: 0.8719000906500907[Parallel(n_jobs=1)]: Using backend SequentialBackend with 1 concurrent workers.
[Parallel(n_jobs=1)]: Done   1 out of   1 | elapsed:    0.2s remaining:    0.0s
[Parallel(n_jobs=1)]: Done  33 out of  33 | elapsed:   10.3s finished

[2022-02-15 13:21:53] Features: 4/15 -- score: 0.8738210092376759[Parallel(n_jobs=1)]: Using backend SequentialBackend with 1 concurrent workers.
[Parallel(n_jobs=1)]: Done   1 out of   1 | elapsed:    0.2s remaining:    0.0s
[Parallel(n_jobs=1)]: Done  32 out of  32 | elapsed:    9.8s finished

[2022-02-15 13:22:03] Features: 5/15 -- score: 0.8785693473193472[Parallel(n_jobs=1)]: Using backend SequentialBackend with 1 concurrent workers.
[Parallel(n_jobs=1)]: Done   1 out of   1 | elapsed:    0.2s remaining:    0.0s
[Parallel(n_jobs=1)]: Done  31 out of  31 | elapsed:    9.9s finished

[2022-02-15 13:22:13] Features: 6/15 -- score: 0.8861505007338341[Parallel(n_jobs=1)]: Using backend SequentialBackend with 1 concurrent workers.
[Parallel(n_jobs=1)]: Done   1 out of   1 | elapsed:    0.3s remaining:    0.0s
[Parallel(n_jobs=1)]: Done  30 out of  30 | elapsed:   10.4s finished

[2022-02-15 13:22:23] Features: 7/15 -- score: 0.8937478416645085[Parallel(n_jobs=1)]: Using backend SequentialBackend with 1 concurrent workers.
[Parallel(n_jobs=1)]: Done   1 out of   1 | elapsed:    0.2s remaining:    0.0s
[Parallel(n_jobs=1)]: Done  29 out of  29 | elapsed:   10.6s finished

[2022-02-15 13:22:34] Features: 8/15 -- score: 0.9003793274626609[Parallel(n_jobs=1)]: Using backend SequentialBackend with 1 concurrent workers.
[Parallel(n_jobs=1)]: Done   1 out of   1 | elapsed:    0.2s remaining:    0.0s
[Parallel(n_jobs=1)]: Done  28 out of  28 | elapsed:    9.1s finished

[2022-02-15 13:22:43] Features: 9/15 -- score: 0.9032283303116637[Parallel(n_jobs=1)]: Using backend SequentialBackend with 1 concurrent workers.
[Parallel(n_jobs=1)]: Done   1 out of   1 | elapsed:    0.3s remaining:    0.0s
[Parallel(n_jobs=1)]: Done  27 out of  27 | elapsed:    9.8s finished

[2022-02-15 13:22:53] Features: 10/15 -- score: 0.9022705689372357[Parallel(n_jobs=1)]: Using backend SequentialBackend with 1 concurrent workers.
[Parallel(n_jobs=1)]: Done   1 out of   1 | elapsed:    0.3s remaining:    0.0s
[Parallel(n_jobs=1)]: Done  26 out of  26 | elapsed:    8.3s finished

[2022-02-15 13:23:01] Features: 11/15 -- score: 0.9022732668566001[Parallel(n_jobs=1)]: Using backend SequentialBackend with 1 concurrent workers.
[Parallel(n_jobs=1)]: Done   1 out of   1 | elapsed:    0.2s remaining:    0.0s
[Parallel(n_jobs=1)]: Done  25 out of  25 | elapsed:    7.4s finished

[2022-02-15 13:23:09] Features: 12/15 -- score: 0.9032283303116636[Parallel(n_jobs=1)]: Using backend SequentialBackend with 1 concurrent workers.
[Parallel(n_jobs=1)]: Done   1 out of   1 | elapsed:    0.2s remaining:    0.0s
[Parallel(n_jobs=1)]: Done  24 out of  24 | elapsed:    7.6s finished

[2022-02-15 13:23:16] Features: 13/15 -- score: 0.902281360614694[Parallel(n_jobs=1)]: Using backend SequentialBackend with 1 concurrent workers.
[Parallel(n_jobs=1)]: Done   1 out of   1 | elapsed:    0.2s remaining:    0.0s
[Parallel(n_jobs=1)]: Done  23 out of  23 | elapsed:    7.3s finished

[2022-02-15 13:23:24] Features: 14/15 -- score: 0.9041779979279979[Parallel(n_jobs=1)]: Using backend SequentialBackend with 1 concurrent workers.
[Parallel(n_jobs=1)]: Done   1 out of   1 | elapsed:    0.2s remaining:    0.0s
[Parallel(n_jobs=1)]: Done  22 out of  22 | elapsed:    7.4s finished

[2022-02-15 13:23:31] Features: 15/15 -- score: 0.907976668393335
In [73]:
# Capturando o nome das variáveis preditoras.
bfSfs = tFeatures.columns[list(sfs.k_feature_idx_)]

# Exibindo o nome das variáveis preditoras.
bfSfs
Out[73]:
Index(['age', 'policy_deductable', 'insured_zip', 'capital-loss', 'witnesses',
       'injury_claim', 'insured_sex_dummy', 'insured_occupation_dummy',
       'insured_hobbies_dummy', 'incident_date_dummy', 'incident_type_dummy',
       'collision_type_dummy', 'incident_severity_dummy',
       'incident_state_dummy', 'police_report_available_dummy'],
      dtype='object')
In [74]:
# Capturando os resultados obtidos pela Técnica Forward Selection.
sc = pd.DataFrame(sfs.get_metric_dict())

# Capturando os scores e o nome das Features, gerados a cada busca.
sc = sc.loc[['cv_scores', 'feature_names'], :].transpose()

# Capturando o nome das features utilizadas em cada avaliação.
featureNames = sc.feature_names

# Criando índices com o número de Features utilizadas em cada avaliação.
columns = [str(i) + ' Feature' if i == 1 else str(i) + ' Features' for i in range(1, sc.shape[0] + 1)]

# Remodelando os dados do DataFrame para serem plotados.
fs = pd.DataFrame()

for i in range(1, sc.shape[0] + 1):

    # Atribui os primeiros scores ao DataFrame, caso esteja vazio.

    if sc.empty:
        fs = pd.DataFrame(sc['cv_scores'][i], columns = [columns[i - 1]])
    else:
        fs[columns[i - 1]] = sc['cv_scores'][i]
In [75]:
# Plotando os scores da acurácia, obtida pelas features selecionadas em cada fase de busca, segundo a técnica Forward Selection.
utlex.plotBoxplot (
    data   = fs,
    title  = 'Acurácia das melhores Features encontradas pelo técnica Forward Selection',
    xaxis  = 'Features selecionadas'
)
In [76]:
# Transpondo a Série Temporal.
fs = fs.transpose()

# Criando uma nova coluna, com os nomes das Features utilizadas, em cada avaliação no DataFrame.
fs['featuresNames'] = [', '.join(f) for f in featureNames]

# Exibindo o nome das features utilizadas em cada avaliação.
fs[['featuresNames']]
Out[76]:
featuresNames
1 Feature incident_severity_dummy
2 Features policy_deductable, incident_severity_dummy
3 Features policy_deductable, insured_hobbies_dummy, inci...
4 Features policy_deductable, insured_hobbies_dummy, coll...
5 Features policy_deductable, insured_hobbies_dummy, inci...
6 Features age, policy_deductable, insured_hobbies_dummy,...
7 Features age, policy_deductable, insured_zip, insured_h...
8 Features age, policy_deductable, insured_zip, capital-l...
9 Features age, policy_deductable, insured_zip, capital-l...
10 Features age, policy_deductable, insured_zip, capital-l...
11 Features age, policy_deductable, insured_zip, capital-l...
12 Features age, policy_deductable, insured_zip, capital-l...
13 Features age, policy_deductable, insured_zip, capital-l...
14 Features age, policy_deductable, insured_zip, capital-l...
15 Features age, policy_deductable, insured_zip, capital-l...

6.2.5 Extra Trees Classifier

O Extremely Randomized Trees Classifier (Extra Trees Classifier) é um tipo de técnica de aprendizagem de conjunto que agrega os resultados de várias árvores de decisão descorrelacionadas coletadas em uma “floresta” para produzir seu resultado de classificação. Em conceito, é muito semelhante a um Classificador Random Forest e só difere na forma de construção das árvores de decisão na floresta.

Cada árvore de decisão na floresta de árvores extras é construída a partir da amostra de treinamento original. Então, em cada nó de teste, cada árvore é fornecida com uma amostra aleatória de k recursos do conjunto de recursos a partir do qual cada árvore de decisão deve selecionar o melhor recurso para dividir os dados com base em alguns critérios matemáticos (normalmente o índice de Gini). Essa amostra aleatória de recursos leva à criação de várias árvores de decisão não correlacionadas.

Para realizar a seleção de características usando a estrutura de floresta acima, durante a construção da floresta, para cada característica, a redução total normalizada nos critérios matemáticos usados ​​na decisão da característica de divisão (Índice de Gini se o Índice de Gini for usado na construção de floresta) é computado. Esse valor é chamado de Importância Gini do recurso. Para realizar a seleção de recursos, cada recurso é ordenado em ordem decrescente de acordo com a Importância Gini de cada recurso e o usuário seleciona os k principais recursos de acordo com sua escolha.

In [77]:
# Definindo qual conjunto de dados, já escalado, deve ser utilizado.
tFeatures = trainFeaturesMM

# Instanciando um objeto da classe ExtraTreesClassifier.
modelETC = ExtraTreesClassifier()

# Computando os scores de cada feature.
modelETC.fit (
    X = tFeatures, 
    y = trainTarget
)

# Inserindo Scores obtidos em uma Série Temporal.
featuresImpETC = pd.Series(data = modelETC.feature_importances_, index = tFeatures.columns)

# Ordenando o nome das variáveis preditoras segundo seu score em ordem decrescente.
bfEtc = featuresImpETC.sort_values(ascending = False)
In [78]:
# Plotando um gráfico de barras, dos scores gerados para as features, a partir da técnica utilizada.
utlex.plotBar (
    data        = bfEtc, 
    title       = 'Scores das melhores features com o Extra Trees Classifier', 
    yaxis       = 'Features', 
    xaxis       = 'Scores', 
    orientation = 'h'
)
In [79]:
# Capturando o nome das variáveis preditoras.
bfEtc = bfEtc.index

# Exibindo o nome das variáveis preditoras.
bfEtc
Out[79]:
Index(['incident_severity_dummy', 'policy_csl_dummy', 'incident_state_dummy',
       'total_claim_amount', 'police_report_available_dummy',
       'authorities_contacted_dummy', 'insured_hobbies_dummy',
       'property_damage_dummy', 'incident_city_dummy', 'collision_type_dummy',
       'incident_date_dummy', 'property_claim', 'witnesses', 'bodily_injuries',
       'incident_type_dummy', 'injury_claim', 'number_of_vehicles_involved',
       'policy_deductable', 'incident_hour_of_the_day',
       'incident_location_dummy', 'insured_zip', 'policy_bind_date_dummy',
       'insured_education_level_dummy', 'auto_model_dummy',
       'insured_occupation_dummy', 'auto_make_dummy', 'capital-gains',
       'policy_state_dummy', 'policy_annual_premium',
       'insured_relationship_dummy', 'auto_year', 'age', 'capital-loss',
       'months_as_customer', 'insured_sex_dummy', 'umbrella_limit'],
      dtype='object')

6.2.6 Random Forest Importance

O Random Forest, é um dos algoritmos de aprendizado de máquina mais populares. É um dos mais bem-sucedidos porque fornece, em geral, um bom desempenho preditivo, baixo overfitting e é de fácil interpretabilidade.

Essa interpretabilidade é dada pela facilidade de se derivar a importância de cada variável na árvore de decisão. Em outras palavras, é fácil calcular o quanto cada variável está contribuindo para a decisão do modelo.

O Random Forest consiste em 4-12 centenas de árvores de decisão, cada uma delas construída sobre uma extração aleatória das observações do conjunto de dados e uma extração aleatória das características. Nem toda árvore vê todas as características ou todas as observações, e isso garante que as árvores sejam descorrelacionadas e, portanto, menos sujeitas a sobreajuste. Cada árvore também é uma sequência de perguntas sim-não com base em um único recurso ou em uma combinação de recursos. Em cada nó (isto é em cada questão), os três dividem o conjunto de dados em 2 depósitos, cada um deles hospedando observações que são mais semelhantes entre si e diferentes das do outro bloco. Portanto, a importância de cada recurso é derivada do quão "puro" cada um dos blocos é.

Para classificação, a medida de impureza é a impureza de Gini ou o ganho / entropia de informação. Para regressão, a medida de impureza é a variância. Portanto, ao treinar uma árvore, é possível calcular o quanto cada recurso diminui a impureza. Quanto maior for a diminuição da impureza que um recurso gerar, mais importante ele será. Em florestas aleatórias, a diminuição da impureza de cada recurso pode ser calculada em média entre as árvores para determinar a importância final da variável.

In [80]:
# Definindo qual conjunto de dados, já escalado, deve ser utilizado.
tFeatures = trainFeaturesMM

# Instanciando um objeto da classe RandomForestClassifier.
rfImp = RandomForestClassifier (
    n_estimators = 200,
    random_state = 0
)

# Treinando o classificador com o conjunto de dados de treino.
rfImp.fit(
    X = tFeatures, 
    y = trainTarget
)

# Prevendo os scores das features dos dados de treino.
pred = rfImp.predict(tFeatures)

# Convertendo os scores para um DataFrame.
featuresImpRf = pd.Series(data = rfImp.feature_importances_, index = tFeatures.columns)

# Capturando os scores de cada uma das features.
bfRf = featuresImpRf.nlargest(15)
In [81]:
# Plotando um gráfico de barras, dos scores gerados para as features, a partir da técnica utilizada.
utlex.plotBar (
    data        = bfRf,
    title       = 'Scores das melhores features com o Random Forest', 
    yaxis       = 'Features', 
    xaxis       = 'Scores', 
    orientation = 'h'
)
In [82]:
# Capturando o nome das variáveis preditoras.
bfRf = bfRf.index

# Exibindo o nome das variáveis preditoras.
bfRf
Out[82]:
Index(['incident_severity_dummy', 'property_claim', 'insured_hobbies_dummy',
       'total_claim_amount', 'incident_date_dummy', 'incident_location_dummy',
       'insured_zip', 'injury_claim', 'policy_bind_date_dummy',
       'policy_annual_premium', 'authorities_contacted_dummy',
       'incident_state_dummy', 'incident_hour_of_the_day', 'auto_model_dummy',
       'months_as_customer'],
      dtype='object')

6.2.7 PCA

A Análise de componente principal (Principal Component Analysis - PCA) é uma técnica de redução de dimensionalidade linear que pode ser utilizada para extrair informações de um espaço de alta dimensão projetando-as em um subespaço de dimensão inferior. Ele tenta preservar as partes essenciais que têm mais variação dos dados e remover as partes não essenciais com menos variação. As dimensões nada mais são do que recursos que representam os dados.

Uma coisa importante a se notar sobre o PCA é que é uma técnica de redução de dimensionalidade não supervisionada. Você pode agrupar os pontos de dados semelhantes com base na correlação de recursos entre eles sem qualquer supervisão (ou rótulos).

In [83]:
# Aplicando a técnica PCA, para criar 10 Componentes, a partir dos dados de treino e de teste.
trainFeaturesPCA, testFeaturesPCA =  utlpca.pcaTransform(train = trainFeatures, test = testFeatures)

6.2.8 RFE

RFE é um algoritmo de seleção de recurso do tipo wrapper. Isso significa que um algoritmo de aprendizado de máquina diferente é fornecido e usado no núcleo do método, é empacotado pelo RFE e usado para ajudar a selecionar recursos. Isso contrasta com as seleções de recursos com base em filtro que pontuam cada recurso e selecionam os recursos com a maior (ou menor) pontuação.

Tecnicamente, o RFE é um algoritmo de seleção de recursos no estilo wrapper que também usa a seleção de recursos com base em filtro internamente.

O RFE funciona procurando por um subconjunto de recursos começando com todos os recursos no conjunto de dados de treinamento e removendo com sucesso os recursos até que o número desejado permaneça.

Isso é obtido ajustando-se o algoritmo de aprendizado de máquina usado no núcleo do modelo, classificando os recursos por importância, descartando os recursos menos importantes e reajustando o modelo. Este processo é repetido até que um determinado número de recursos permaneça.

Os recursos são pontuados usando o modelo de aprendizado de máquina fornecido ou usando um método estatístico.

In [84]:
# Definindo qual conjunto de dados, já escalado, deve ser utilizado.
tFeatures = trainFeaturesMM

# Instanciando um objeto da classe RFE para selecionar as melhores variáveis preditoras, utilizando o algoritmo XGBClassifer.
rfe = RFE (
    estimator            = xgb.XGBClassifier(use_label_encoder=False,eval_metric='logloss'), 
    n_features_to_select = 15
)

# Capturando as melhores variáveis preditoras.
rfeFit = rfe.fit (
    X = tFeatures, 
    y = trainTarget
)
In [85]:
# Capturando o nome das variáveis preditoras.
bfRfe = tFeatures.columns[rfeFit.support_]

# Exibindo o nome das variáveis preditoras.
bfRfe
Out[85]:
Index(['policy_deductable', 'number_of_vehicles_involved', 'bodily_injuries',
       'witnesses', 'policy_bind_date_dummy', 'policy_csl_dummy',
       'insured_hobbies_dummy', 'incident_date_dummy', 'incident_type_dummy',
       'collision_type_dummy', 'incident_severity_dummy',
       'authorities_contacted_dummy', 'incident_state_dummy',
       'incident_location_dummy', 'police_report_available_dummy'],
      dtype='object')

7. Modelagem Preditiva

7.1 Criando modelos preditivos e avaliando suas Performances

Iremos criar modelos preditivos, com diferentes algoritmos, e com as Features em diferentes escalas. Também criaremos classificadores utilizando a técnica PCA. Por fim, selecionaremos os modelos que obtiveram as maiores acurácias.

In [86]:
# Treinando classificadores, a partir dos componentes criados pela técnica PCA.
resultsPCA = utlml.classifiersTraining (
    features = trainFeaturesPCA, 
    tTarget  = trainTarget
)
LR: 0.730674 (0.045551)
LDA: 0.754313 (0.043492)
KNN: 0.720279 (0.046614)
CART: 0.686909 (0.047545)
RF: 0.748661 (0.038926)
XGBoost: 0.737242 (0.035469)
In [87]:
# Plotando os scores, da acurácia dos classificadores treinados, em boxplots.
utlex.plotBoxplot(data = resultsPCA[0])

O algoritmo Random Forest, foi o que obteve a melhor acurácia, para o conjunto de componentes do PCA.

In [88]:
# Treinando classificadores, a partir da escala, e da técnica de Feature Selection utilizada.
resultsMM = utlml.classifiersTraining (
    features = trainFeaturesMM, 
    tTarget  = trainTarget
)
LR: 0.811195 (0.047263)
LDA: 0.803621 (0.046350)
KNN: 0.687053 (0.048934)
CART: 0.825490 (0.027532)
RF: 0.867206 (0.029609)
XGBoost: 0.892821 (0.030512)
In [89]:
# Plotando os scores, da acurácia dos classificadores treinados, em boxplots.
utlex.plotBoxplot(data = resultsMM[0])

O algoritmo XGBoost, foi o que obteve a melhor acurácia, para o conjunto dados transformados pelo algoritmo MinMaxScaler.

In [90]:
# Treinando classificadores, a partir da escala, e da técnica de Feature Selection utilizada.
resultsSS = utlml.classifiersTraining (
    features = trainFeaturesSS, 
    tTarget  = trainTarget
)
LR: 0.804564 (0.045250)
LDA: 0.803621 (0.046350)
KNN: 0.673729 (0.050272)
CART: 0.823594 (0.033382)
RF: 0.870036 (0.019366)
XGBoost: 0.892821 (0.030512)
In [91]:
# Plotando os scores, da acurácia dos classificadores treinados, em boxplots.
utlex.plotBoxplot(data = resultsSS[0])

O algoritmo XGBoost, foi o que obteve a melhor acurácia, para o conjunto dados transformados pelo algoritmo StandardScaler.

In [92]:
# Treinando classificadores, a partir da escala, e da técnica de Feature Selection utilizada.
resultsND = utlml.classifiersTraining (
    features = trainFeaturesNormDistribuition, 
    tTarget  = trainTarget
)
LR: 0.818787 (0.037433)
LDA: 0.824465 (0.029945)
KNN: 0.665229 (0.042084)
CART: 0.832183 (0.032514)
RF: 0.866280 (0.028691)
XGBoost: 0.892821 (0.030512)
In [93]:
# Plotando os scores, da acurácia dos classificadores treinados, em boxplots.
utlex.plotBoxplot(data = resultsND[0])

O algoritmo XGBoost, foi o que obteve a melhor acurácia, para o conjunto dados transformados pelo algoritmo Box-Cox.

In [94]:
# Treinando classificadores, a partir da escala, e da técnica de Feature Selection utilizada.
resultsNorm = utlml.classifiersTraining (
    features = trainFeaturesNormalized, 
    tTarget  = trainTarget
)
LR: 0.767637 (0.043129)
LDA: 0.803621 (0.046350)
KNN: 0.712704 (0.057221)
CART: 0.832156 (0.030413)
RF: 0.870036 (0.029016)
XGBoost: 0.892821 (0.030512)
In [95]:
# Plotando os scores, da acurácia dos classificadores treinados, em boxplots.
utlex.plotBoxplot(data = resultsNorm[0])

O algoritmo XGBoost, foi o que obteve a melhor acurácia, para o conjunto dados transformados pelo algoritmo Normalize.

7.2 Realizando previsões para o conjunto de dados de teste

7.2.1 Otimizando Classificadores

Agora que já testamos diferentes algoritmos com diversas escalas, iremos escolher os melhores modelos criados e otimizar seus parâmetros.

7.2.1.1 Algoritmo Random Forest

Iremos buscar pelos melhores parâmetros, para criar um modelo com o algoritmo Random Forest.

In [96]:
# Definindo qual conjunto de dados de treino, já escalado, deve ser utilizado e a sua variável target.
trainX = trainFeaturesNormDistribuition
trainY = trainTarget

# Definindo qual conjunto de dados de teste, já escalado, deve ser utilizado e a sua variável target.
testX = testFeaturesNormDistribuition
testY = testTarget

# Definindo os valores que devem ser testados, em cada um dos parâmetros do modelo especificado.
paramGrid = dict (
    n_estimators      = [50, 100, 250], 
    max_depth         = [None, 2, 4, 6],
    max_features      = ['auto', 'sqrt', 'log2'], 
    min_samples_split = [2, 5],
    min_samples_leaf  = [1, 2, 5]
)

# Criando uma instância da classe do modelo Random Forest.
model = RandomForestClassifier()

# Criando o grid, para fazer a busca dos melhores parâmetros para o modelo.
grid = GridSearchCV(estimator = model, param_grid = paramGrid, cv = 10, verbose = True, n_jobs = -1)

# Buscando pelos melhores parâmetros para o modelo.
grid.fit(trainX, trainY)

# Exibindo a configuração, do melhor modelo treinado.
print("\n" + "Melhores Parâmetros para o Modelo:" + "\n\n", grid.best_estimator_)
Fitting 10 folds for each of 216 candidates, totalling 2160 fits

Melhores Parâmetros para o Modelo:

 RandomForestClassifier(max_features='sqrt', n_estimators=250)
In [97]:
# Criando o modelo, com a melhor configuração encontrada.
classifierRF = grid.best_estimator_

# Treinando o modelo com os dados de treino.
classifierRF.fit(X = trainX, y = trainY)
Out[97]:
RandomForestClassifier(max_features='sqrt', n_estimators=250)
In [98]:
# Calculando a acurácia do modelo para o conjunto de dados de treino.
scoreTrainRF = accuracy_score(trainY, classifierRF.predict(trainX))

# Visualizando o resultado.
print('Acurácia para os dados de treino: ' + str(scoreTrainRF))
Acurácia para os dados de treino: 1.0
In [99]:
# Calculando a acurácia do modelo para o conjunto de dados de teste.
scoreTestRF = accuracy_score(testY, classifierRF.predict(testX))

# Visualizando o resultado.
print('Acurácia  para os dados de teste: ' + str(scoreTestRF))
Acurácia  para os dados de teste: 0.8517699115044248
7.2.1.2 Algoritmo Xgboost

Iremos buscar pelos melhores parâmetros, para criar um modelo com algoritmo Xgboost.

In [100]:
# Definindo qual conjunto de dados de treino, já escalado, deve ser utilizado e a sua variável target.
trainX = trainFeaturesNormDistribuition
trainY = trainTarget

# Definindo qual conjunto de dados de teste, já escalado, deve ser utilizado e a sua variável target.
testX = testFeaturesNormDistribuition
testY = testTarget

# Definindo os valores que devem ser testados, em cada um dos parâmetros do modelo especificado.
paramGrid = dict (
    missing          = [np.nan],
    booster          = ['gbtree', 'gblinear'],
    n_estimators     = [50, 100, 200, 300, 350, 400], 
    learning_rate    = [0.025, 0.03], 
    nthread          = [4], 
    seed             = [100]    
)

# Criando uma instância da classe do modelo Xgboost.
model = xgb.XGBClassifier(use_label_encoder=False,eval_metric='logloss')

# Criando o grid, para fazer a busca dos melhores parâmetros para o modelo.
grid = GridSearchCV(estimator = model, param_grid = paramGrid, cv = 10, verbose = True, n_jobs = -1)

# Buscando pelos melhores parâmetros para o modelo.
grid.fit(trainX, trainY)

# Exibindo a configuração, do melhor modelo treinado.
print("\n" + "Melhores Parâmetros para o Modelo:" + "\n\n", grid.best_estimator_)
Fitting 10 folds for each of 24 candidates, totalling 240 fits

Melhores Parâmetros para o Modelo:

 XGBClassifier(base_score=0.5, booster='gbtree', colsample_bylevel=1,
              colsample_bynode=1, colsample_bytree=1, enable_categorical=False,
              eval_metric='logloss', gamma=0, gpu_id=-1, importance_type=None,
              interaction_constraints='', learning_rate=0.03, max_delta_step=0,
              max_depth=6, min_child_weight=1, missing=nan,
              monotone_constraints='()', n_estimators=400, n_jobs=4, nthread=4,
              num_parallel_tree=1, predictor='auto', random_state=100,
              reg_alpha=0, reg_lambda=1, scale_pos_weight=1, seed=100,
              subsample=1, tree_method='exact', use_label_encoder=False, ...)
In [101]:
# Criando o modelo, com a melhor configuração encontrada.
classifierXGB = grid.best_estimator_

# Treinando o modelo com os dados de treino.
classifierXGB.fit(X = trainX, y = trainY)
Out[101]:
XGBClassifier(base_score=0.5, booster='gbtree', colsample_bylevel=1,
              colsample_bynode=1, colsample_bytree=1, enable_categorical=False,
              eval_metric='logloss', gamma=0, gpu_id=-1, importance_type=None,
              interaction_constraints='', learning_rate=0.03, max_delta_step=0,
              max_depth=6, min_child_weight=1, missing=nan,
              monotone_constraints='()', n_estimators=400, n_jobs=4, nthread=4,
              num_parallel_tree=1, predictor='auto', random_state=100,
              reg_alpha=0, reg_lambda=1, scale_pos_weight=1, seed=100,
              subsample=1, tree_method='exact', use_label_encoder=False, ...)
In [102]:
# Calculando a acurácia do modelo para o conjunto de dados de treino.
scoreTrainXGB = accuracy_score(trainY, classifierXGB.predict(trainX))

# Visualizando o resultado.
print('Acurácia para os dados de treino: ' + str(scoreTrainXGB))
Acurácia para os dados de treino: 1.0
In [103]:
# Calculando a acurácia do modelo para o conjunto de dados de teste.
scoreTestXGB = accuracy_score(testY, classifierXGB.predict(testX))

# Visualizando o resultado.
print('Acurácia  para os dados de teste: ' + str(scoreTestXGB))
Acurácia  para os dados de teste: 0.8672566371681416

7.2.2 Avaliando as métricas do melhor classificador para os dados de teste

O melhor classificador treinado, utiliza o algoritmo Xgboost com as features em distribuição normal. Salvaremos as configurações desse modelo em um arquivo .sav.

In [104]:
# Salvando o modelo preditivo especificado.
utlml.saveModel(name = 'classifierXGB', model = classifierXGB)
Modelo salvo!
In [105]:
# Carregando o modelo preditivo especificado.
classifierXGB = utlml.loadModel(name = 'classifierXGB')
Modelo carregado!

Para analisar melhor a performance do modelo, precisamos determinar os valores das probabilidades geradas nas previsões.

In [106]:
# Definindo qual conjunto de dados de treino, já escalado, deve ser utilizado e a sua variável target.
trainX = trainFeaturesNormDistribuition
testX  = testFeaturesNormDistribuition

# Realizando as predições das probabilidades, dos dados de treino e teste, para o modelo selecionado.
predTrainProb = classifierXGB.predict_proba(trainX)[:,1]
predTestProb  = classifierXGB.predict_proba(testX)[:,1]

Iremos binarizar as previsões, e os valores a serem previstos, dos conjuntos de dados de treino e teste.

In [107]:
# Definindo as classes positiva e negativa da variável target.
labelPositive = 'Yes'
labelNegative = 'No'

# Criando uma lista com as categorias das classes.
labels = [labelPositive, labelNegative]

# Convertendo dados da variável target, dos dados de treino, para utilizar as labels especificadas.
trainTargetLabels = [labelPositive if t == 1 else labelNegative for t in trainTarget]
trainPredLabels   = [labelPositive if t >= 0.5 else labelNegative for t in predTrainProb]

# Convertendo dados da variável target, dos dados de teste, para utilizar as labels especificadas.
testTargetLabels = [labelPositive if t == 1 else labelNegative for t in testTarget]
testPredLabels   = [labelPositive if t >= 0.5 else labelNegative for t in predTestProb]
In [108]:
# Criando uma Confusion Matrix para avaliar as previsões feitas para os dados de treino.
cm = utlml.confusionMatrix(yTrue = trainTargetLabels, yPred = trainPredLabels)

# Exibindo a Confusion Matrix.
cm
Out[108]:
Actual Yes No classError
Predicted
Yes 532 0 0.0
No 0 522 0.0

Não observamos ocorrência de falsos negativos ou falsos positivos para o conjunto de dados de treino.

In [109]:
# Criando uma Confusion Matrix para avaliar as previsões feitas para os dados de teste.
cm = utlml.confusionMatrix(yTrue = testTargetLabels, yPred = testPredLabels)

# Exibindo a Confusion Matrix.
cm
Out[109]:
Actual Yes No classError
Predicted
Yes 198 37 0.157447
No 23 194 0.105991

Nos dados de teste, constatamos a ocorrência de falsos negativos, mas a proporção de falsos positivos é predominante.

In [110]:
# Plotando a Confusion Matrix dos dados de teste em um gráfico.
utlml.plotConfusionMatrix (
    data   = cm.drop(labels= 'classError', axis = 1), 
    labels = labels
)

Vamos calcular algumas estatísticas, baseadas nos resultados gerados pelo modelo, para os dados de teste.

In [111]:
# Calculando os scores de diferentes métricas, com base nas previsões geradas pelo modelo, para os dados de teste.
utlml.getClassificationMetrics(yTrue = testTargetLabels, predProb = predTestProb)
Out[111]:
Metrics
Accuracy 0.867257
95% CI for Accuracy (0.8359766131511799, 0.8985366611851033)
Kappa 0.734747
Recall (Sensitivity) 0.895928
Specificity 0.839827
Pos Pred Value 0.842553
Neg Pred Value 0.894009
Precision 0.842553
Avarage Precision 0.805752
Prevalence 0.488938
Detection Rate 0.438053
Detection Prevalence 0.519912
F1 0.868421
ROC AUC 0.934281
Error 0.132743
95% CI for Error (0.10146333881489665, 0.16402338684882012)
Balanced Accuracy 0.867877
Positive Class Yes

Finalizamos esta análise, concluindo que o algoritmo Xgboost, gerou o modelo com a melhor acurácia. Os scores alcançados para os conjuntos de dados foram:

  • Dados de treino: 1.000000.
  • Dados de teste: 0.867257.

Entre em Contato!

Caso tenha alguma dúvida ou sugestão, entre em contato.

Github Linkedin E-mail Portfólio